using System;
using System.Collections.Generic;
using System.Windows.Forms;
using Microsoft.TeamFoundation.VersionControl.Client;
using System.Xml;
using System.Xml.XPath;


namespace Ssis.TfsCheckIn
{

    [Serializable]
    public class SsisCheckInPolicy : PolicyBase
    {
        
        public override string Description
        {
            get { return "Remind users to adhere to SSIS coding standards"; }
        }

        // This is a string that is stored with the policy definition on the source
        // control server.  If a user does not have our policy plugin installed, this string
        // will be displayed.  We can use this as an opportunity to explain to the user
        // how they might go about installing our policy plugin.
        public override string InstallationInstructions
        {
            //Change this later.
            get { return "To install this policy, execute SSIS.CheckInPolicyInstaller.msi."; }
        }

        // This string is the type of our policy.  It will be displayed to the user in a list
        // of all installed policy types when they are creating a new policy.
        public override string Type
        {
            get { return "SSIS Policy"; }
        }

        // This string is a description of the type of our policy.  It will be displayed to the
        // user when they select our policy type in the list of policies installed on the system
        // as mentioned above.
        public override string TypeDescription
        {
            get { return "This policy checks that SSIS packages adhere to BIPA policies."; }
        }

        // This method is invoked by the policy framework when the user creates a new checkin
        // policy or edits an existing checkin policy.  We can use this as an opportunity to
        // display UI specific to this policy type allowing the user to change the parameters
        // of the policy.
        public override bool Edit(IPolicyEditArgs args)
        {
            // no configuration to save
            return true;
        }

        // This method performs the actual evaluation.  It is called by the policy framework at various points in time
        // when policy should be evaluated.
        public override PolicyFailure[] Evaluate()
        {
            List<PolicyFailure> failures = new List<PolicyFailure>(); //Make it easy for us to add failures

            foreach (PendingChange pendingChange in PendingCheckin.PendingChanges.CheckedPendingChanges)
            {
                //Is item to be checked-in a SSIS package?
                if (pendingChange.ServerItem.ToLower().EndsWith(".dtsx"))  //allow for upper case extensions (just in case)
                {
                    //Load the package into an XML document
                    XmlReader packageXML = GetPackageXMLReader(pendingChange.LocalItem);

                    CheckPackageDisableEventHandlers(packageXML, failures, pendingChange);

                    CheckDelayValidationForRawFileSource(packageXML, failures, pendingChange);
                }
            }
            return failures.ToArray();
        }

        /*This method will add a PolicyFailure to List<PolicyFailure> failures if the package has DisableEventHandlers=TRUE
         */
        private void CheckPackageDisableEventHandlers(XmlReader reader, List<PolicyFailure> failures, PendingChange pendingChange)
        {
            XmlNamespaceManager namespaceManager = new XmlNamespaceManager(reader.NameTable);
            namespaceManager.AddNamespace("DTS", "www.microsoft.com/SqlServer/Dts");

            XmlDocument pkgDocument = new XmlDocument();
            pkgDocument.Load(reader);

            XmlNode node = pkgDocument.SelectSingleNode("/DTS:Executable/DTS:Property[@DTS:Name='DisableEventHandlers']", namespaceManager);

            if (node.InnerText == "-1")
            {
                failures.Add(new PolicyFailure(
                                        String.Format(pendingChange.ChangeType + " : " + "Pending change on {0} cannot be committed. DisableEventHandlers=TRUE",
                                                        pendingChange.LocalItem), this));
            }
        }


        private void CheckDelayValidationForRawFileSource(XmlReader reader, List<PolicyFailure> failures, PendingChange pendingChange)
        {

        }

        /*  Convert package to an XML reader that can then be queried using XPath
         */
        private XmlReader GetPackageXMLReader(string fileName)
        {
            /*OBSELETE CODE!!
            XmlTextReader txtReader = new XmlTextReader(fileName);
            XmlValidatingReader reader = new XmlValidatingReader(txtReader);
            reader.ValidationType = ValidationType.DTD;
            */

            XmlReaderSettings settings = new XmlReaderSettings();
            settings.ConformanceLevel = ConformanceLevel.Document;
            XmlReader reader = XmlReader.Create(fileName);

            return reader;
        }

        // This method is called if the user double-clicks on a policy failure in the UI.
        // We can handle this as we please, potentially prompting the user to perform
        // some activity that would eliminate the policy failure.
        public override void Activate(PolicyFailure failure)
        {
            if (failure.Message.Contains("DisableEventHandlers=TRUE"))
            {
                MessageBox.Show("Please set package property DisableEventHandlers=FALSE.", "How to fix your policy failure");
            }
            else
            {
                //Shouldn't be any other condition!
            }

        }

        // This method is called if the user presses F1 when a policy failure is active in the UI.
        // We can handle this as we please, displaying help in whatever format is appropriate.
        // For this example, we'll just pop up a dialog.
        public override void DisplayHelp(PolicyFailure failure)
        {
            MessageBox.Show("This policy enforces BIPA policies for SSIS.", "Prompt Policy Help");
        }
    }
}

